/*******************************************************************
 * Copyright (C) yel_hb-USTC, 2012                                
 *                                                                  
 * FILE NAME             :  utils.cpp                                 
 * PRINCIPAL AUTHOR      :  yel_hb                               
 * MODULE NAME           :  UTILS                             
 * LANGUAGE              :  C++                                      
 * TARGET ENVIRONMENT    :  windows                                   
 * DATE OF FIRST RELEASE :  2012/12/18                              
 * DESCRIPTION           :  implement some useful util methods.
 ******************************************************************/

/*
 * Revision log:
 *
 * Created by yel_hb,2012/12/18
 * Modified by yel_hb,2012/12/23
 *
 */
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
#include <ctime>
#include <vector>

#include "utils.h"
#include "dmvector.h"
#include "kahansum.h"
#include "median.h"
using namespace std;

void write_data ( string fileName, vector<DMVector> vlist, vector<int> vp)
{
	ofstream foutput;
	vector<DMVector>::iterator ix;
	vector<int>::iterator ixp;
	foutput.open ( fileName.c_str(), ios::out );
	
	if ( !foutput )
	{
		cerr << "Open file Error!" << endl;
		return;
	}

	for ( ix = vlist.begin(), ixp = vp.begin(); ix != vlist.end(); ++ix, ++ixp )
	{
		int i;
		for ( i = 0; i < (*ix).size(); ++i )
		{
			foutput << setprecision(15)  << setiosflags(ios::scientific) << (*ix).get(i) << " ";
		}
		foutput << (*ixp) << endl;
	}
	
	foutput << endl;
	foutput.close();
}

void write_data ( string fileName, vector<DMVector> vlist )
{
	ofstream foutput;
	vector<DMVector>::iterator ix;
	foutput.open ( fileName.c_str(), ios::out );
	
	if ( !foutput )
	{
		cerr << "Open file Error!" << endl;
		return;
	}

	for ( ix = vlist.begin(); ix != vlist.end(); ++ix)
	{
		int i;
		for ( i = 0; i < (*ix).size(); ++i )
		{
			if ( i != 0 )
				foutput << " ";
			foutput << setprecision(15)  << setiosflags(ios::scientific) << (*ix).get(i);
		}
		foutput << endl;
	}
	foutput.close();
}

vector<DMVector> read_data ( string fileName )
{
	vector<DMVector> vlist;
	string tmps;
	ifstream finput ( fileName.c_str(), ios::in );
	int i, size;

	if ( !finput )
	{
		cerr << "Open file Error!" << endl;
		return NULL;
	}

	size = 1;
	// check the dimension of vector
	if ( !finput.eof() )
	{
		getline ( finput, tmps, '\n' );

		i = 0;
		while ( !( tmps[i] == '\0' || tmps[i] == '\n' ))
		{
			if ( tmps[i] == ' ' )
				size++;
			i++;
		}
	}

	finput.seekg ( 0, ios::beg);
	while ( !finput.eof() )
	{
		DMVector dmvector(size);
		for ( i = 0; i < size; ++i )
		{
			finput >> tmps;
			if ( tmps.length() == 0 )
				return vlist;
			dmvector.set ( i, atof( tmps.c_str()));
		}
		vlist.push_back ( dmvector );
	}
	finput.close();
	return vlist;
}

vector<DMVector> read_data ( string fileName, vector<int> &vp )
{
	vector<DMVector> vlist;
	vp.clear();
	int cla;
	string tmps;
	ifstream finput ( fileName.c_str(), ios::in );
	int i, size;

	if ( !finput )
	{
		cerr << "Open file Error!" << endl;
		return NULL;
	}

	size = 1;
	// check the dimension of vector
	if ( !finput.eof() )
	{
		getline ( finput, tmps, '\n' );

		i = 0;
		while ( !( tmps[i] == '\0' || tmps[i] == '\n' ))
		{
			if ( tmps[i] == ' ' )
				size++;
			i++;
		}
	}
	
	finput.seekg ( 0, ios::beg);
	while ( !finput.eof() )
	{
		DMVector dmvector(size - 1);
		for ( i = 0; i < size - 1; ++i )
		{
			finput >> tmps;
			if ( tmps.length() == 0 )
				return vlist;
			dmvector.set ( i, atof( tmps.c_str()));
		}
		vlist.push_back ( dmvector );

		finput >> cla;
		vp.push_back ( cla );
	}
	finput.close();
	return vlist;
}

vector<double> vector_mean ( vector<DMVector> vlist )
{
	vector<DMVector>::iterator ix;
	vector<double> vb;
	KahanSum kahan;
	int i, size;

	size = vlist.size();
	for ( i = 0; i < vlist[0].size(); ++i )
	{
		kahan.reset();
		for ( ix = vlist.begin(); ix != vlist.end(); ++ix )
		{
			kahan.add ( (*ix).get ( i ));
		}
		vb.push_back ( kahan.get_sum() / ( size * 1.0 ));
	}

	return vb;
}

vector<double> vector_median ( vector<DMVector> vlist )
{
	vector<DMVector>::iterator ix;
	int i;
	vector<double> vb;
	Median median;

	for ( i = 0; i < vlist[0].size(); ++i )
	{
		median.reset();
		for ( ix = vlist.begin(); ix != vlist.end(); ++ix )
		{
			median.add ( (*ix).get( i ));
		}
		vb.push_back ( median.get_median() );
	}

	return vb;
}

/*
 * Box-Muller method
 */
double gaussianNormal() 
{
	double u = ((double) rand() / (RAND_MAX)) * 2 - 1;
	double v = ((double) rand() / (RAND_MAX)) * 2 - 1;
	double r = u * u + v * v;

	if ( r == 0 || r > 1 )
		return gaussianNormal();

	double c = sqrt ( -2 * log(r) / r );

	return u * c;
}